#include <thread>
#include <atomic>
#include <vector>
#include <functional>
#include "lock_thread_safe_queue.h"


class join_threads
{
  std::vector<std::thread>& threads;
public:
  explicit join_threads(std::vector<std::thread>& threads_):
    threads(threads_)
  {}
  ~join_threads()
  {
    for(unsigned long i=0;i<threads.size();++i)
    {
      if(threads[i].joinable())
        threads[i].join();
    }
  }
};

class thread_pool
{
  // done标志和worker_queue必须在threads数组之前声明，而threads数组必须在joiner前声明，这样就能确保成员以正确的顺序析构
  std::atomic_bool done;
  thread_safe_queue<std::function<void()>> work_queue;
  std::vector<std::thread> threads;
  join_threads joiner;

  void worker_thread()
  {
    while(!done)  // 4
    {
      std::function<void()> task;
      if(work_queue.try_pop(task))  // 5
      {
        task();  // 6
      }
      else
      {
        std::this_thread::yield();  // 7
      }
    }
  }

public:
  thread_pool():
    done(false),joiner(threads)
  {
    unsigned const thread_count=std::thread::hardware_concurrency();  // 8

    try
    {
      for(unsigned i=0;i<thread_count;++i)
      {
        // 新建线程
        threads.push_back(std::thread(&thread_pool::worker_thread,this));
      }
    }
    catch(...)
    {
      done=true;  // 10
      throw;
    }
  }

  ~thread_pool()
  {
    done=true;  // 11
  }

  template<typename FunctionType>
  void submit(FunctionType f)
  {
    work_queue.push(std::function<void()>(f));  // 12
  }
};